import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:flutter_clx_base/api/proxy.dart';
import 'package:flutter_clx_base/api/transformer.dart';
import 'package:flutter_clx_base/utils/log_utils.dart';
import 'package:flutter_clx_base/utils/toast_util.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';

// ignore: depend_on_referenced_packages
import 'package:http_mock_adapter/http_mock_adapter.dart';
export 'package:dio/dio.dart';
export 'package:dio/io.dart';

export 'proxy.dart';

abstract class BaseDio {
  final dio = Dio(
    BaseOptions(
        connectTimeout: const Duration(seconds: 10),
        receiveTimeout: const Duration(seconds: 10),
        contentType: Headers.jsonContentType,
        responseType: ResponseType.plain
        // Transform the response data to a String encoded with UTF8.
        // The default value is [ResponseType.JSON].
        ),
  );

  //初始化配置dio实例
  void initConfig() {
    dio.options.baseUrl = setBaseUrl();
    dio.options.headers = setHeaders();
    // 配置JSON转换器
    dio.interceptors.add(getHeadersInterceptor());
    dio.interceptors.add(getLogInterceptor());
    //配置代理
    setProxyUri(dio, isProdEnv());
  }

  final jsonTransformer = MyTransformer();

  String setBaseUrl();

  // 设置请求头拦截器
  Interceptor getHeadersInterceptor();

  // mock数据适配器
  DioAdapter getMockAdapter() => DioAdapter(dio: dio);

  // 是否是生产环境，默认为true，
  // 生产环境不设置代理，默认不设置
  bool isProdEnv() => true;

  // 设置log拦截器
  Interceptor getLogInterceptor() => _setLogInterceptor();

  Map<String, dynamic>? setHeaders() => _setHeaders();

  //设置代理
  HttpClientAdapter _setProxy() {
    return IOHttpClientAdapter();
  }

  HttpClientAdapter setProxy() => _setProxy();

  void onLoginExpire() => _onLoginExpire();

  void onNetSuccess(Response response, NetSuccessCallback successCallback,
          NetErrorCallback? errorCallback) =>
      _onNetSuccess(response, successCallback, errorCallback);

  // 登录过期的处理
  void _onLoginExpire() {
    ToastUtil.showToast("登录过期，请重新登录");
  }

  Interceptor _setLogInterceptor() {
    return PrettyDioLogger(
        requestHeader: true,
        requestBody: true,
        responseBody: true,
        responseHeader: false,
        error: true,
        compact: true,
        maxWidth: 120);
  }

  //设置请求头
  Map<String, dynamic>? _setHeaders() {
    return {
      'Content-Type': 'application/json;charset=UTF-8',
    };
  }

  // 构建网络请求
  void request({
    required String requestUrl,
    required Method method,
    Options? options,
    Map<String, dynamic>? queryParameters,
    Map<String, dynamic>? data,
    required NetSuccessCallback successCallback,
    NetErrorCallback? errorCallback,
  }) async {
    try {
      final Response response = await dio.request(
        requestUrl,
        queryParameters: queryParameters,
        data: data,
        options: _checkOptions(method.value, options),
      );
      onNetSuccess(response, successCallback, errorCallback);
    } on DioException catch (e) {
      if (e.response != null) {
        logger.e(
            "请求错误：${e.response!.statusCode} ${e.response!.requestOptions.path}");
      } else {
        // Something happened in setting up or sending the request that triggered an Error
        logger.e("请求错误：${e.error}");
      }
      await errorCallback?.call(500, "服务器请求错误");
    }
  }

  // 构建网络请求同步请求
  Future<dynamic> requestSync({
    required String requestUrl,
    required Method method,
    Options? options,
    Map<String, dynamic>? queryParameters,
    Object? data,
  }) async {
    try {
      final Response response = await dio.request(
        requestUrl,
        queryParameters: queryParameters,
        data: data,
        options: _checkOptions(method.value, options),
      );
      try {
        final String data = response.data.toString();
        final bool isCompute = data.length > 10 * 1024;
        // loggerNoStack.i('isCompute:$isCompute');
        final Map<String, dynamic> map = isCompute
            ? await jsonTransformer.parseJson(data)
            : jsonTransformer.parseAndDecode(data);
        var responseCode = map['code']?.toString();
        if (responseCode == "A0230") {
          logger.e("登录过期：${map['msg']}");
          onLoginExpire();
        }
        return map;
      } catch (e) {
        logger.e("数据解析错误：${e.toString()}");
        return {"code": 400, "message": "数据解析错误"};
      }
    } on DioException catch (e) {
      if (e.response != null) {
        logger.e(
            "请求错误：${e.response!.statusCode} ${e.response!.requestOptions.path}");
      } else {
        // Something happened in setting up or sending the request that triggered an Error
        logger.e("请求错误：${e.error}");
      }
      return {"code": 500, "message": "服务器请求错误"};
    }
  }

  // 处理网络请求成功逻辑
  void _onNetSuccess(Response response, NetSuccessCallback successCallback,
      NetErrorCallback? errorCallback) async {
    try {
      final String data = response.data.toString();
      final bool isCompute = data.length > 10 * 1024;
      // loggerNoStack.i('isCompute:$isCompute');
      final Map<String, dynamic> map = isCompute
          ? await jsonTransformer.parseJson(data)
          : jsonTransformer.parseAndDecode(data);
      var responseCode = map['code']?.toString();
      if (responseCode == "A0230") {
        logger.e("登录过期：${map['msg']}");
        onLoginExpire();
        return;
      }

      if (map['code'] == 0 || map['code'] == '0') {
        await successCallback.call(map['data']);
      } else {
        logger.e("请求错误：${map['code']} ${map['msg']}");
        await errorCallback?.call(map['code'], map['msg']);
      }
    } catch (e) {
      logger.e("数据解析错误：${e.toString()}");
      await errorCallback?.call(400, "数据解析错误");
    }
  }
}

Options _checkOptions(String method, Options? options) {
  options ??= Options();
  options.method = method;
  return options;
}

typedef NetSuccessCallback = Function(dynamic data);
typedef NetSuccessListCallback = Function(List? list);
typedef NetErrorCallback = Function(dynamic code, String? msg);

enum Method {
  get,
  post,
  put,
  patch,
  delete,
}

extension MethodExtension on Method {
  String get value => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'][index];
}
